package src.solver.mundo;

import java.util.HashMap;

import src.solver.sintaxis.ArbolSintaxis;
import src.solver.sintaxis.NodoSintaxis;

public class Solver 
{
	private Equation arbol;
	
	
	public Solver(Equation arbol)
	{
		this.arbol = arbol;
		start(arbol.getVariable());
	}
	
	public void sumarIguales(NodoSintaxis nodo)
	{
		NodoSintaxis hijoIzq = nodo.darHijoIzq();		
		NodoSintaxis hijoDer = nodo.darHijoDer();
		if(nodo.toString().equals(ArbolSintaxis.MAS))
		{
			if(hijoIzq.toString().equals(hijoDer.toString()))
			{
				nodo.cambiarContenido(ArbolSintaxis.POR);
				hijoIzq.cambiarContenido("2");
				nodo.cambiarHijoIzq(hijoIzq);
			}			
		}
		else if(nodo.toString().equals(ArbolSintaxis.MENOS))
		{
			if(hijoIzq.toString().equals(hijoDer.toString()))
			{
				nodo.cambiarContenido("0");
				nodo.cambiarHijoIzq(null);
				nodo.cambiarHijoDer(null);
			}
		}
		
	}
	
	public void prodIguales(NodoSintaxis nodo)
	{
		NodoSintaxis hijoIzq = nodo.darHijoIzq();		
		NodoSintaxis hijoDer = nodo.darHijoDer();
		if(nodo.toString().equals(ArbolSintaxis.POR))
		{
			if(hijoIzq.toString().equals(hijoDer.toString()))
			{
				nodo.cambiarContenido(ArbolSintaxis.DOS_EXP);
				nodo.cambiarHijoCent(hijoIzq);
			}
		}
		else if(nodo.toString().equals(ArbolSintaxis.SOBRE))
		{
			if(hijoIzq.toString().equals(hijoDer.toString()))
			{
				nodo.cambiarContenido("1");
				nodo.cambiarHijoIzq(null);
				nodo.cambiarHijoDer(null);
			}
		}
	}
	
	public void sumarCero(NodoSintaxis nodo)
	{
		NodoSintaxis hijoIzq = nodo.darHijoIzq();
		NodoSintaxis hijoDer = nodo.darHijoDer();
		if(hijoIzq.toString().equals("0")||hijoDer.toString().equals("0"))
		{
			String contenido = hijoIzq.toString().equals("0")?hijoDer.toString():hijoIzq.toString();
			nodo.cambiarContenido(contenido);
			nodo.cambiarHijoIzq(null);
			nodo.cambiarHijoDer(null);
		}
	}
	
	public void prod1(NodoSintaxis operacion)
	{
		NodoSintaxis hijoIzq = operacion.darHijoIzq();
		NodoSintaxis hijoDer = operacion.darHijoDer();
		if(operacion.toString().equals(ArbolSintaxis.POR) && (hijoIzq.toString().equals("1")||hijoDer.toString().equals("1")))
		{
			NodoSintaxis n = hijoIzq.toString().equals("1")?hijoDer:hijoIzq;
			operacion = n;
			operacion.cambiarHijoIzq(null);
			operacion.cambiarHijoDer(null);
		}
		else if(hijoDer.toString().equals("1")&& operacion.toString().equals(ArbolSintaxis.SOBRE))
		{
			operacion = hijoIzq;
			operacion.cambiarHijoIzq(null);
			operacion.cambiarHijoDer(null);
		}
			
	}
	
	
	public void dosExp1o0(NodoSintaxis nodo)
	{
		if(nodo.darHijoCent().equals("1"))
		{
			nodo.cambiarContenido("2");
			nodo.cambiarHijoCent(null);
		}
		else if(nodo.darHijoCent().equals("0"))
		{
			nodo.cambiarContenido("1");
			nodo.cambiarHijoCent(null);
		}
	}
	
	
	public void log12(NodoSintaxis nodo)
	{
		if(nodo.darHijoCent().equals("1"))
		{
			nodo.cambiarContenido("0");
			nodo.cambiarHijoCent(null);
			System.out.println("=< log 1 = 0 >");
		}
		if(nodo.darHijoCent().equals("2"))
		{
			nodo.cambiarContenido("1");
			nodo.cambiarHijoCent(null);
			System.out.println("=< log 2 = 1 >");
		}
	}
	
	public void start(String var)
	{
		NodoSintaxis raiz = arbol.darRaiz();
		int limit = arbol.getLimit();
		int i = 0;
		while (i <= limit && (raiz.darHijoIzq().toString() != arbol.getVariable() || raiz.darHijoDer().toString() != arbol.getVariable())) {
			NodoSintaxis izq = arbol.darRaiz().darHijoIzq();
			NodoSintaxis der = arbol.darRaiz().darHijoDer();
			if(izq.contarVariable(var)<der.contarVariable(var))
			{
				raiz.cambiarHijoIzq(der);
				raiz.cambiarHijoDer(izq);
				NodoSintaxis temp = izq;
				izq = der;
				der = temp;
				
			}
			HashMap<String, String> oppMono = arbol.darOppMono();
			if(oppMono.containsKey(izq.toString()))
			{
				invertirMono(raiz, der, izq);
			}
			varALaDerecha(raiz.darHijoIzq(), var);
			varALaDerecha(raiz.darHijoDer(), var);
			reducir(raiz.darHijoIzq(), var);
			reducir(raiz.darHijoDer(), var);
			varAlLadoIzq(raiz, izq, der, var);
			constAlLadoDer(raiz, izq, der, var);
			i++;
		}
		

	}
	
	public void invertirMono(NodoSintaxis raiz, NodoSintaxis der, NodoSintaxis izq)
	{
		if(izq.toString().equals(ArbolSintaxis.DOS_EXP))
		{
			izq = izq.darHijoCent();
			NodoSintaxis nuevo = new NodoSintaxis(ArbolSintaxis.LOG);
			nuevo.cambiarHijoCent(der.darHijoCent());
			der = nuevo;
			raiz.cambiarHijoIzq(izq);
			raiz.cambiarHijoDer(der);
			arbol.cambiarRaiz(raiz);
		}
		else if(izq.toString().equals(ArbolSintaxis.LOG))
		{
			izq = izq.darHijoCent();
			NodoSintaxis nuevo = new NodoSintaxis(ArbolSintaxis.DOS_EXP);
			nuevo.cambiarHijoCent(der.darHijoCent());
			der = nuevo;
			raiz.cambiarHijoIzq(izq);
			raiz.cambiarHijoDer(der);
			arbol.cambiarRaiz(raiz);
		}
		else if(izq.toString().equals(ArbolSintaxis.EXP_DOS))
		{
			izq = izq.darHijoCent();
			NodoSintaxis nuevo = new NodoSintaxis(ArbolSintaxis.RAIZ);
			nuevo.cambiarHijoCent(der.darHijoCent());
			der = nuevo;
			raiz.cambiarHijoIzq(izq);
			raiz.cambiarHijoDer(der);
			arbol.cambiarRaiz(raiz);
		}
		else if(izq.toString().equals(ArbolSintaxis.RAIZ))
		{
			izq = izq.darHijoCent();
			NodoSintaxis nuevo = new NodoSintaxis(ArbolSintaxis.EXP_DOS);
			nuevo.cambiarHijoCent(der.darHijoCent());
			der = nuevo;
			raiz.cambiarHijoIzq(izq);
			raiz.cambiarHijoDer(der);
			arbol.cambiarRaiz(raiz);
		}
	}
	
	public void varALaDerecha(NodoSintaxis nodo, String var)
	{
		NodoSintaxis izq = nodo.darHijoIzq();
		NodoSintaxis der = nodo.darHijoDer();
		NodoSintaxis residuo = null;
		NodoSintaxis temp = null;
		if(nodo.toString().equals(ArbolSintaxis.MAS))
		{
			if(!der.toString().equals(var))
			{
				residuo = der;
				nodo = izq;
				temp = new NodoSintaxis(ArbolSintaxis.MAS);
				temp.cambiarHijoIzq(nodo.darHijoIzq());
				temp.cambiarHijoDer(residuo);
				nodo.cambiarHijoIzq(temp);					
			}
			if(izq.toString().equals(var))
			{
				nodo.cambiarHijoDer(izq);
				nodo.cambiarHijoIzq(der);
			}
							
			
		}
		else if(nodo.toString().equals(ArbolSintaxis.POR))
		{
			if(!der.toString().equals(var))
			{
				residuo = der;
				nodo = izq;
				temp = new NodoSintaxis(ArbolSintaxis.POR);
				temp.cambiarHijoIzq(nodo.darHijoIzq());
				temp.cambiarHijoDer(residuo);
				nodo.cambiarHijoIzq(temp);					
			}
			if(izq.toString().equals(var))
			{
				nodo.cambiarHijoDer(izq);
				nodo.cambiarHijoIzq(der);
			}
			else if(izq.toString().equals(ArbolSintaxis.POR))
			{
				varALaDerecha(izq, var);
			}				
			
		}
		arbol.imprimir();
		
	}
	
	public void reducir(NodoSintaxis nodo, String var)
	{
		NodoSintaxis izq = nodo.darHijoIzq();
		NodoSintaxis der = nodo.darHijoDer();
		if(izq!= null && der!= null)
		{
			if(nodo.toString().equals(ArbolSintaxis.MAS) && der.toString().equals(var))
			{
				if(izq.toString().equals(ArbolSintaxis.MAS) && izq.darHijoDer().toString().equals(var))
				{
					izq = izq.darHijoIzq();
					NodoSintaxis v = new NodoSintaxis(ArbolSintaxis.MAS);
					v.cambiarHijoDer(new NodoSintaxis(var));
					v.cambiarHijoIzq(new NodoSintaxis(var));
					nodo.cambiarHijoDer(v);
					sumarIguales(nodo);
					
				}
			}
			if(nodo.toString().equals(ArbolSintaxis.POR) && der.toString().equals(var))
			{
				if(izq.toString().equals(ArbolSintaxis.POR) && izq.darHijoDer().toString().equals(var))
				{
					izq = izq.darHijoIzq();
					NodoSintaxis v = new NodoSintaxis(ArbolSintaxis.POR);
					v.cambiarHijoDer(new NodoSintaxis(var));
					v.cambiarHijoIzq(new NodoSintaxis(var));
					nodo.cambiarHijoDer(v);
					prodIguales(nodo);
					
				}
			}
			reducir(izq, var);
		}
		arbol.imprimir();
		
	}
	
	private void constAlLadoDer(NodoSintaxis raiz, NodoSintaxis izq, NodoSintaxis der, String var)
	{
		NodoSintaxis alOtroLado = new NodoSintaxis();
		NodoSintaxis temp = null;
		if(izq.toString().equals(ArbolSintaxis.MAS))
		{
			 if(!izq.darHijoDer().hayVariable(var))
			 {
				 alOtroLado = izq.darHijoDer();
				 izq = izq.darHijoIzq();
				 temp = new NodoSintaxis(ArbolSintaxis.MENOS);
				 temp.cambiarHijoIzq(der);
				 temp.cambiarHijoDer(alOtroLado);
				 der = temp;
			 }
		}
		else if(izq.toString().equals(ArbolSintaxis.MENOS) || izq.toString().equals(ArbolSintaxis.MENOS_LARGO))
		{
			 if(!izq.darHijoDer().hayVariable(var))
			 {
				 alOtroLado = izq.darHijoDer();
				 izq = izq.darHijoIzq();
				 temp = new NodoSintaxis(ArbolSintaxis.MAS);
				 temp.cambiarHijoIzq(der);
				 temp.cambiarHijoDer(alOtroLado);
				 der = temp;
			 }
		}
		else if(izq.toString().equals(ArbolSintaxis.POR))
		{
			 if(!izq.darHijoDer().hayVariable(var))
			 {
				 alOtroLado = izq.darHijoDer();
				 izq = izq.darHijoIzq();
				 temp = new NodoSintaxis(ArbolSintaxis.SOBRE);
				 temp.cambiarHijoIzq(der);
				 temp.cambiarHijoDer(alOtroLado);
				 der = temp;
			 }
		}
		else if(izq.toString().equals(ArbolSintaxis.SOBRE))
		{
			 if(!izq.darHijoDer().hayVariable(var))
			 {
				 alOtroLado = izq.darHijoDer();
				 izq = izq.darHijoIzq();
				 temp = new NodoSintaxis(ArbolSintaxis.POR);
				 temp.cambiarHijoIzq(der);
				 temp.cambiarHijoDer(alOtroLado);
				 der = temp;
				 
			 }
		}
		raiz.cambiarHijoIzq(izq);
		raiz.cambiarHijoDer(der);
		arbol.imprimir();
	}
	
	private void varAlLadoIzq(NodoSintaxis raiz, NodoSintaxis izq, NodoSintaxis der, String var)
	{
		NodoSintaxis alOtroLado = new NodoSintaxis();
		NodoSintaxis temp = null;
		if(der.toString().equals(ArbolSintaxis.MAS))
		{
			 if(!der.darHijoIzq().hayVariable(var))
			 {
				 alOtroLado = der.darHijoIzq();
				 der = der.darHijoDer();
				 temp = new NodoSintaxis(ArbolSintaxis.MENOS);
				 temp.cambiarHijoIzq(izq);
				 temp.cambiarHijoDer(alOtroLado);
				 izq = temp;
			 }
		}
		else if(der.toString().equals(ArbolSintaxis.MENOS) || der.toString().equals(ArbolSintaxis.MENOS_LARGO))
		{
			if(!der.darHijoIzq().hayVariable(var))
			 {
				 alOtroLado = der.darHijoIzq();
				 der = der.darHijoDer();
				 temp = new NodoSintaxis(ArbolSintaxis.MAS);
				 temp.cambiarHijoIzq(izq);
				 temp.cambiarHijoDer(alOtroLado);
				 izq = temp;
			 }
		}
		else if(der.toString().equals(ArbolSintaxis.POR))
		{
			if(!der.darHijoIzq().hayVariable(var))
			 {
				 alOtroLado = der.darHijoIzq();
				 der = der.darHijoDer();
				 temp = new NodoSintaxis(ArbolSintaxis.SOBRE);
				 temp.cambiarHijoIzq(izq);
				 temp.cambiarHijoDer(alOtroLado);
				 izq = temp;
			 }
		}
		else if(der.toString().equals(ArbolSintaxis.SOBRE))
		{
			if(!der.darHijoIzq().hayVariable(var))
			 {
				 alOtroLado = der.darHijoIzq();
				 der = der.darHijoDer();
				 temp = new NodoSintaxis(ArbolSintaxis.POR);
				 temp.cambiarHijoIzq(izq);
				 temp.cambiarHijoDer(alOtroLado);
				 izq = temp;
			 }
		}
		raiz.cambiarHijoIzq(izq);
		raiz.cambiarHijoDer(der);
		arbol.imprimir();
	}
	
	
//	public void factorComun(NodoSintaxis sumaPr)
//	{
//		NodoSintaxis hijoDer = sumaPr.darHijoDer();
//		
//		NodoSintaxis hijoIzq = sumaPr.darHijoIzq();
//		
//		if(hijoDer.toString().equals(ArbolSintaxis.POR)&&hijoIzq.toString().equals(ArbolSintaxis.POR))
//		{
//			NodoSintaxis factorIzq1 = hijoIzq.darHijoIzq();
//			NodoSintaxis factorIzq2 = hijoIzq.darHijoDer();
//			NodoSintaxis factorDer1 = hijoDer.darHijoIzq();
//			NodoSintaxis factorDer2 = hijoDer.darHijoDer();
//			
//			if(factorIzq1.toString().equals())
//		}
//		
//	}
}
